/*
 * Copyright 2009 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.devtools.simple.compiler;

import com.google.devtools.simple.classfiles.ClassFile;
import com.google.devtools.simple.compiler.Compiler;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

import junit.framework.TestCase;

/**
 * Smoke tests for the Simple compiler.
 *
 * <p>Compiles and executes a suite of tests written in Simple.
 *
 * @author Herbert Czymontek
 */
public class CompilerSmokeTest extends TestCase {

  /*
   * Classloader for loading classes generated by the Simple compiler..
   */
  private static class InjectionClassLoader extends ClassLoader {
    // List of generated classes
    final List<ClassFile> classes;

    InjectionClassLoader(List<ClassFile> classes, ClassLoader parent) {
      super(parent);
      this.classes = classes;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
      for (ClassFile classFile : classes) {
        if (classFile.getName().equals(name)) {
          byte[] classData = classFile.generate();
          return defineClass(name, classData, 0, classData.length);
        }
      }
      return findClass(name);
    }
  }

  /**
   * Compiles and executes Simple SmokeTest suite.
   */
  public void testSmokeTest() throws ClassNotFoundException, NoSuchMethodException,
      IllegalAccessException, IOException, Throwable {
    // Compile the sources of the Simple project into memory
    List<ClassFile> classes = Compiler.compileForUnitTesting(
        new Project(new File("tests/com/google/devtools/simple/compiler/SmokeTest/simpleproject",
            "project.properties")));
    assertNotNull(classes);

    // Use special classloader to load classes from memory
    ClassLoader loader = new InjectionClassLoader(classes, getClass().getClassLoader());
    Class<?> smokeTestClass = loader.loadClass("com.google.devtools.simple.smoketest.SmokeTest");

    // Look for entry point and invoke tests
    Method smokeTestEntryPoint = smokeTestClass.getMethod("RunSmokeTests");
    try {
      smokeTestEntryPoint.invoke(null);
    } catch (InvocationTargetException e) {
      throw e.getCause();
    }
  }
}
